Skip to content

fix(injection-defense): detect single-bracket [INST]/[/INST] delimiter (#353) - #373

Merged
gnanirahulnutakki merged 1 commit into
devfrom
fix/353-inst-delimiter
Aug 11, 2026
Merged

fix(injection-defense): detect single-bracket [INST]/[/INST] delimiter (#353)#373
gnanirahulnutakki merged 1 commit into
devfrom
fix/353-inst-delimiter

Conversation

@gnanirahulnutakki

Copy link
Copy Markdown
Member

Root cause

crates/injection-defense/src/pattern.rs — the delimiter_injection
signature was r"\[\[INST\]\]|<\|im_start\|>". The \[\[INST\]\] alternative
requires a doubled bracket, so it only fired on [[INST]]. The delimiter
attackers actually use to smuggle a new turn/role — the single-bracket
Llama/Mistral chat-template markers [INST] and [/INST] — matched nothing
and passed the filter unflagged. Verified in-tree: the other delimiter
signatures (system_directive_delimiter, role_tag_delimiter, <|im_start|>)
did not cover this form, so single-bracket [INST] was a genuine gap.

Fix

Widen the one regex to:

(?i)\[\s*/?\s*INST\s*\]|<\|im_start\|>|<</?SYS>>
  • Matches [INST], [/INST], the doubled [[INST]] (inner match), and
    internal-whitespace forms like [ INST ].
  • Adds the closely related Llama system-block delimiters <<SYS>> / <</SYS>>
    that pair with [INST].
  • Keeps <|im_start|> (ChatML).
  • Anchored to exactly INST/SYS + closing bracket, so benign bracketed text
    [INSTALL], [INSTRUCTIONS], [INFO], [INSTANCE], array indexing
    a[0] — does not match. No false positives.

Tightest possible scope: one signature line changed, no new dependencies,
Cargo.lock untouched.

Regression tests

New crates/injection-defense/tests/inst_delimiter_variants.rs, both directions:

  • inst_delimiter_variants_are_blocked[INST], [/INST], [[INST]],
    [ INST ], <s>[INST], <<SYS>>…<</SYS>> all → Block + DelimiterAbuse.
  • benign_bracketed_text_is_not_flagged[INSTALL], [INSTRUCTIONS],
    [INFO], a[0], [INST. of Tech], [instance] all → Allow, no
    DelimiterAbuse.

Verification (all green locally)

  • cargo test -p ardur-injection-defense — pass (incl. 2 new tests)
  • cargo test -p ardur-e2e-tests — pass
  • cargo clippy -p ardur-injection-defense --all-targets -- -D warnings — clean
  • cargo fmt --check — clean

Fixes #353

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: f3e6e2bf-3ddd-45eb-a8a9-379a66c804c4

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/353-inst-delimiter

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

gnanirahulnutakki added a commit that referenced this pull request Aug 11, 2026
…uinn-proto, resync Cargo.lock (#387)

Three coupled fixes that together restore a mergeable `dev`.

1. cargo-deny (required check) is failing on every open PR and on `dev`
   itself with a single finding:

       error[unmaintained]: bitmaps is unmaintained
         ID: RUSTSEC-2026-0247
         Solution: No safe upgrade is available!

   `bitmaps` is transitive only, via matrix-sdk -> imbl ->
   imbl-sized-chunks. It is an unmaintained notice, not a vulnerability,
   and cargo-deny itself reports that no safe upgrade exists. That is
exactly the class `[advisories].ignore` already documents (bincode via
   syntect, paste via fastembed, proc-macro-error2 via Matrix/Teloxide,
rustls-pemfile via qdrant-client), so it is ignored on the same terms.
   Vulnerability advisories are still upgraded rather than ignored — see
   (2).

2. Patch the two crates behind all five open Dependabot alerts. Both are
   reachable from the workspace and both have released fixes:

     - russh 0.62.2 -> 0.62.5 (direct dep of crates/terminal), closing
       GHSA-m65r-rprj-r5rg (CVE-2026-68930, channel-scoped server
       callbacks reachable without an open channel), GHSA-g9hv-x236-4qp3
       (pre-auth X25519 wrong-length panic), GHSA-cqjc-rmpq-xprq
       (post-auth pty-req panic) and GHSA-5xvq-cp9x-6p6r (pre-auth
       all-zero Curve25519 encode_mpint OOB).
     - quinn-proto 0.11.14 -> 0.11.16 (transitive), closing the one HIGH
       alert, GHSA-4w2j-m93h-cj5j (remote memory exhaustion from
       unbounded out-of-order stream reassembly).

Dependabot did raise these as #385 and #382, but against `main`, where
   they fail DCO; `dev` never received them.

3. Resync Cargo.lock, which had drifted from the manifests: it was
   missing `ardur-delegate-tool` (#332) and `ardur-durability` (#327)
   along with tar/filetime/xattr, and still carried stale entries.
   `.github/workflows/release.yml` builds `--locked`, so a release cut
from `dev` would have failed to resolve. `cargo metadata --locked` now
   succeeds.

Verified locally: `cargo deny check` reports advisories/bans/licenses/
sources all ok; `cargo fmt --check`, `cargo build --workspace` and
`cargo clippy --workspace --all-targets -D warnings` are clean.

---

**Why this lands first:** `cargo-deny` is a required check and is
currently red on *every* open PR (#368, #369, #370, #372, #373, #374,
#375 all show exactly one failing required check, and it is this one).
Nothing can merge into `dev` until the advisory is resolved.

Signed-off-by: GR <gnanirn@gmail.com>
#353)

The delimiter_injection signature only matched the doubled [[INST]] and
<|im_start|>, so the real single-bracket [INST] / [/INST] Llama/Mistral
chat-template delimiter — the form an attacker actually uses to smuggle a
new turn/role — passed the filter unflagged.

Widen the regex to (?i)\[\s*/?\s*INST\s*\]|<\|im_start\|>|<</?SYS>>:
matches [INST], [/INST], the doubled [[INST]] and internal-whitespace forms,
plus the closely related Llama system delimiters <<SYS>> / <</SYS>>. Anchored
to exactly INST/SYS so [INSTALL], [INSTRUCTIONS], [INFO], a[0] do not match.

Add crates/injection-defense/tests/inst_delimiter_variants.rs covering both
directions: the [INST] variants are now blocked as DelimiterAbuse, and
representative benign bracketed text is not falsely flagged.

Fixes #353

Checkpoint: architect/sessions/fix-353-inst-delimiter/journal.md
Signed-off-by: Gnani Nutakki <gnani.nutakki@gmail.com>

Signed-off-by: GR <gnanirn@gmail.com>
@gnanirahulnutakki
gnanirahulnutakki merged commit 3cb5a0a into dev Aug 11, 2026
13 checks passed
@gnanirahulnutakki
gnanirahulnutakki deleted the fix/353-inst-delimiter branch August 11, 2026 21:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant